package com.yuke.cloud.service.uac.service.impl;

import com.google.common.base.Joiner;
import com.yuke.cloud.common.base.constant.GlobalConstant;
import com.yuke.cloud.common.base.dto.UserTokenDto;
import com.yuke.cloud.common.util.PublicUtil;
import com.yuke.cloud.common.util.RedisKeyUtil;
import com.yuke.cloud.service.uac.security.SecurityUtils;
import com.yuke.cloud.service.uac.service.AccRolePermissionService;
import com.yuke.cloud.service.uac.service.AccUserRoleService;
import com.yuke.cloud.service.uac.service.UacPermissionService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.HttpHeaders;
import org.springframework.security.core.Authentication;
import org.springframework.security.oauth2.provider.ClientDetails;
import org.springframework.security.oauth2.provider.ClientDetailsService;
import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.List;
import java.util.Set;

/**
 * The class Uac permission service.
 *
 * @author
 */
@Slf4j
@Component("permissionService")
public class UacPermissionServiceImpl implements UacPermissionService {
	private AntPathMatcher antPathMatcher = new AntPathMatcher();
	private static final String OAUTH2_CLIENT_PREFIX = "yuke-client-";

	@Resource
	private ClientDetailsService clientDetailsService;

	@Resource
	private AccUserRoleService accUserRoleService;

	@Value("${spring.profiles.active}")
	private String env;//当前激活的配置文件

	@Resource
	private AccRolePermissionService accRolePermissionService;

	@Resource
	private RedisTemplate<String, Object> redisTemplate;  // add by wg 20190126

	@Override
	public boolean hasPermission(Authentication authentication, HttpServletRequest request) {
		String currentLoginName = SecurityUtils.getCurrentLoginName();
		Set<String> currentAuthorityUrl = SecurityUtils.getCurrentAuthorityUrl();
		String requestURI = request.getRequestURI();

		log.info("验证权限loginName={}, requestURI={}, hasAuthorityUrl={}", currentLoginName, requestURI, Joiner.on(GlobalConstant.Symbol.COMMA).join(currentAuthorityUrl));
		// 超级管理员 全部都可以访问
		if (StringUtils.equals(currentLoginName, GlobalConstant.Sys.SUPER_MANAGER_LOGIN_NAME)) {
			return true;
		}

		// add by wg 20181220 管理员可以全部访问
		if (accUserRoleService.checkAdminByLoginName(currentLoginName)) {
			return true;
		}

		//todo 开发环境下调试功能接口时，暂时开放所有权限!!20181025
		if ("dev".equals(env)) {
			return true;
		}

		// DEMO项目Feign客户端具有所有权限, 如果需要则在角色权限中控制
		if (currentLoginName.contains(OAUTH2_CLIENT_PREFIX)) {
			ClientDetails clientDetails = clientDetailsService.loadClientByClientId(currentLoginName);
			return clientDetails != null;
		}

		// mod by wg 20190126 改成权限在redis中获取 start
		// add by wg 20181221 权限会放在token的payload中，如果权限的过多，则会导致payload很长，因此改成获取角色方式
//		List<Long> roleIdList = SecurityUtils.getCurrentAuthorityRoleIdList();
//
//		List<String> listUrl = accRolePermissionService.getPermissionUrlListByRoleIds(roleIdList);
//		currentAuthorityUrl.addAll(listUrl);

		String authHeader = request.getHeader(HttpHeaders.AUTHORIZATION);
		String authPrefix = "Bearer ";
		String token = "";
		if (PublicUtil.isNotEmpty(authHeader) && org.apache.commons.lang.StringUtils.startsWithIgnoreCase(authHeader, authPrefix)) {
			token = org.apache.commons.lang.StringUtils.substring(authHeader, authPrefix.length());
		}
		if (PublicUtil.isNotEmpty(token)) {
			UserTokenDto userTokenDto = (UserTokenDto) redisTemplate.opsForValue().get(RedisKeyUtil.getAccessTokenKey(token));
			currentAuthorityUrl.addAll(userTokenDto.getAuthorityUrlList());
		}
		// mod by wg 20190126 改成权限在redis中获取 end

		for (final String authority : currentAuthorityUrl) {
			// DEMO项目放过查询权限
			if (requestURI.contains("query") || requestURI.contains("get") || requestURI.contains("check") || requestURI.contains("select")) {
				return true;
			}
			if (antPathMatcher.match(authority, requestURI)) {
				return true;
			}
		}
		return false;
	}
}
